using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Objects;
using System.Collections.Specialized;

namespace CurriculumData
{
    public class Controller
    {        
        private readonly Entities _context = new Entities();
        
        #region Properties

        public List<DbDataRecord> States { get { return new List<DbDataRecord>(_context.City.Select("it.State").Distinct()); } }

        public List<DbDataRecord> Areas { get { return new List<DbDataRecord>(_context.Position.Select("it.Area").Distinct()); } }

        #endregion

        #region Public Methods
        
        public void Save(Candidate candidate)
        {
            var existingCandidate = GetCandidate(candidate.CandidateId);
            Copy(candidate, existingCandidate);
            _context.SaveChanges();
        }

        public int? Login(string taxNumber, string password)
        {
            var login = _context.Candidate.Where("it.TaxNumber == @TaxNumber && it.Password == @Password", new ObjectParameter("TaxNumber", taxNumber), new ObjectParameter("Password", password));
            var list = new List<Candidate>(login);
            foreach (var candidate in list)
                return candidate.CandidateId;
            return null;
        }

        public Candidate CreateCandidate(string taxNumber, string email)
        {
            var candidates = _context.Candidate.Where("it.TaxNumber == @TaxNumber", new ObjectParameter("TaxNumber", taxNumber));
            var list = new List<Candidate>(candidates);
            if (list.Count != 0)
                return null;
            var newCandidate = new Candidate { TaxNumber = taxNumber, Email = email, Password = Math.Abs(taxNumber.GetHashCode()).ToString() };
            _context.AddToCandidate(newCandidate);
            _context.SaveChanges();
            return newCandidate;
        }

        public List<ListView> GetSubscriptions(int candidateId)
        {
            return new List<ListView>(_context.ListView.Where("it.CandidateId == @CandidateId", new ObjectParameter("CandidateId", candidateId)));
        }

        public void Unsubscribe(int vacancyId, int candidateId)
        {
            var subscribedVacancies = _context.CandidateVacancy.Where("it.CandidateId == @CandidateId && it.VacancyId == @VacancyId", new ObjectParameter("CandidateId", candidateId), new ObjectParameter("VacancyId", vacancyId));
            var list = new List<CandidateVacancy>(subscribedVacancies);
            foreach (var candidateVacancy in list)
            {
                _context.DeleteObject(candidateVacancy);
                _context.SaveChanges();
            }
        }

        public void Subscribe(int candidateId, string area, string subArea, string position)
        {
            var vacancy = new Vacancy {Area = area, SubArea = subArea, Position = position, Opennings = 0};
            _context.AddToVacancy(vacancy);
            _context.SaveChanges();
            Subscribe(vacancy.VacancyId, candidateId);
        }

        public void Subscribe(int vacancyId, int candidateId)
        {
            var vacancies = _context.Vacancy.Where("it.VacancyId == @VacancyId", new ObjectParameter("VacancyId", vacancyId));
            var candidate = GetCandidate(candidateId);
            var list = new List<Vacancy>(vacancies);
            var candidateVacancy = new CandidateVacancy {Candidate = candidate, Vacancy = list[0]};
            _context.AddToCandidateVacancy(candidateVacancy);
            _context.SaveChanges();
        }

        public List<UnsubscribedView> GetUnsubscribed(bool isSpontaneous, int candidateId)
        {
            var unsubscribed = _context.UnsubscribedView.Where("it.CandidateId==@CandidateId", new ObjectParameter("CandidateId", candidateId));
            return new List<UnsubscribedView>(unsubscribed.Where("it.Opennings" + (isSpontaneous ? "==0" : ">0")));
        }

        public Candidate GetCandidate(int candidateId)
        {
            var candidates = _context.Candidate.Where("it.CandidateId == @CandidateId", new ObjectParameter("CandidateId", candidateId));
            var list = new List<Candidate>(candidates);
            foreach (var candidate in list)
                return candidate;
            return null;
        }

        public Candidate GetCopy(Candidate candidate)
        {
            var newCandidate = new Candidate();
            Copy(candidate, newCandidate);
            return newCandidate;
        }

        public List<DbDataRecord> GetProvincies(string state)
        {
            return new List<DbDataRecord>(_context.City.Where("it.State==@State", new ObjectParameter("State", state)).Select("it.Province").Distinct());
        }

        public List<DbDataRecord> GetCities(string state, string province)
        {
            return new List<DbDataRecord>(_context.City.Where("it.State==@State && it.Province==@Province", new ObjectParameter("State", state), new ObjectParameter("Province", province)).Select("it.CityName").Distinct());
        }

        public List<DbDataRecord> GetSubAreas(string area)
        {
            return new List<DbDataRecord>(_context.Position.Where("it.area==@Area", new ObjectParameter("Area", area)).Select("it.subarea").Distinct());
        }

        public List<DbDataRecord> GetPositions(string area, string subarea)
        {
            return new List<DbDataRecord>(_context.Position.Where("it.area==@Area && it.subarea==@SubArea", new ObjectParameter("Area", area), new ObjectParameter("SubArea", subarea)).Select("it.PositionName").Distinct());
        }

        public void Transfer<T>(T entity, IOrderedDictionary values)
        {
            var type = entity.GetType();
            foreach (DictionaryEntry value in values)
            {
                var propertyInfo = type.GetProperty((string)value.Key);
                propertyInfo.SetValue(entity, value.Value, null);
            }
        }

        public void Refresh()
        {
            _context.Refresh(RefreshMode.StoreWins, _context.Candidate);
            _context.Refresh(RefreshMode.StoreWins, _context.ListView);
            _context.Refresh(RefreshMode.StoreWins, _context.Vacancy);
        }

        #endregion

        #region Private Methods
        
        private static void Copy(Candidate source, Candidate target)
        {
            var type = source.GetType();
            var properties = type.GetProperties();
            for (var propertyIndex = 0; propertyIndex < properties.Length; propertyIndex++)
            {
                var propertyInfo = properties[propertyIndex];
                if (!propertyInfo.CanWrite)
                    continue;
                var value = propertyInfo.GetValue(source, null);
                try
                {
                    propertyInfo.SetValue(target, value, null);
                }
                catch
                {
                }
            }
        }

        #endregion
    }
}